


// 登录
void Request_Login(XS_ServerObject objServer, XS_HostObject objHost, struct mg_connection* c, struct mg_http_message* hm)
{
	if ( hm->methodCode == HTTP_GET ) {
		
		// 登录页面
		if ( hm->session ) {
			http_reply(c, 302, "Location: /\r\n", NULL, 0);
		} else {
			LoadPage(c, 200, HTTP_CT_HTML, "login.html");
		}
		
	} else if ( hm->methodCode == HTTP_POST ) {
		
		// 登录请求
		
		// step 1 : 暴力破解防火墙
		xtime tCD = Guard_Check(&c->rem);
		if ( tCD ) {
			str sTime = xrtTimeToStr(tCD, XRT_TIME_FORMAT_DATETIME);
			mg_http_reply(c, 200, HTTP_CT_JSON, "{\"result\": false, \"msg\": \"登录失败尝试次数过多，请于 %s 后再试！\"}", sTime);
			xrtFree(sTime);
			return;
		}
		
		// step 2 : 计算登录密码的 MD5 值
		xvalue tblForm = xrtParseJSON(hm->body.buf, hm->body.len);
		str sUser = xvoTableGetText(tblForm, "username", 8);
		str sPwd = xvoTableGetText(tblForm, "password", 8);
		mg_md5_ctx ctx;
		mg_md5_init(&ctx);
		mg_md5_update(&ctx, sUser, strlen(sUser));
		mg_md5_update(&ctx, "_xPanel_", 8);
		mg_md5_update(&ctx, sPwd, strlen(sPwd));
		uint8 buf[16];
		mg_md5_final(&ctx, buf);
		str sPwdMD5 = xrtHexEncode(buf, 16);
		
		// step 3 : 验证数据库记录
		str sSQL = xrtFormat("SELECT * FROM user WHERE (user = '%s') AND (pwd = '%s')", sUser, sPwdMD5);
		XDO_Recordset objRS = xdoSelect(G_DB, sSQL);
		xrtFree(sPwdMD5);
		xrtFree(sSQL);
		if ( xrsGetRecordCount(objRS) > 0 ) {
			
			// step 4 : 验证用户名 ( 避免碰撞 )
			xrsNext(objRS);
			if ( xrtStrComp(xrsGetValue(objRS, 2), sUser, 0, FALSE) == 0 ) {
				
				// step 5 : 创建用户 Session 表
				str XID = xrtMakeXIDS();
				xvalue tblSession = xvoCreateTable();
				xvoTableSetValue(G_Session, XID, 32, tblSession, TRUE);
				
				// step 6 : 将用户信息填入用户 Session 表
				xvoTableSetText(tblSession, "xid", 3, XID, 0, TRUE);
				xvoTableSetInt(tblSession, "id", 2, xrtStrToI64(xrsGetValue(objRS, 0)));
				xvoTableSetInt(tblSession, "role", 4, xrtStrToI64(xrsGetValue(objRS, 1)));
				xvoTableSetText(tblSession, "user", 4, sUser, 0, FALSE);
				//xvoPrintValue(tblSession, 0, 0, 0, NULL);
				
				// step 7 : 重置防护模块信息
				Guard_Reset(&c->rem);
				
				// step 8 : 返回响应，附带 cookie 信息
				str sHeader;
				if ( xvoTableItemType(tblForm, "remember", 8) == XVO_DT_TEXT ) {
					sHeader = xrtFormat("%sSet-Cookie: XSID=%s; HttpOnly; Max-Age=604800\r\n", HTTP_CT_JSON, XID);
				} else {
					sHeader = xrtFormat("%sSet-Cookie: XSID=%s; HttpOnly\r\n", HTTP_CT_JSON, XID);
				}
				http_reply(c, 200, sHeader, "{\"result\": true, \"msg\": \"登录成功，即将跳转到后台管理页面！\"}", 0);
				xrtFree(sHeader);
				
			} else {
				// 登录失败
				http_reply(c, 200, HTTP_CT_JSON, "{\"result\": false, \"msg\": \"登录失败，请检查用户名密码是否正确！\"}", 0);
				Guard_Failed(&c->rem);
			}
		} else {
			// 登录失败
			http_reply(c, 200, HTTP_CT_JSON, "{\"result\": false, \"msg\": \"登录失败，请检查用户名密码是否正确！\"}", 0);
			Guard_Failed(&c->rem);
		}
		
		// step 9 : 释放记录集和表单
		xvoUnref(tblForm);
		xrsFree(objRS);
		
	} else {
		
		// 其他请求方法返回 404 页面
		LoadPage(c, 404, HTTP_CT_HTML, "status/404.html");
		
	}
}



// 注销登录
void Request_Logout(XS_ServerObject objServer, XS_HostObject objHost, struct mg_connection* c, struct mg_http_message* hm)
{
	if ( (hm->methodCode == HTTP_GET) || (hm->methodCode == HTTP_POST) ) {
		
		// 删除 Session
		if ( hm->session ) {
			str sID = xvoTableGetText(hm->session, "xid", 3);
			xvoTableRemove(G_Session, sID, 0);
		}
		
		// 清除 Cookie 并跳转到登录页
		str sHeader = xrtFormat("%sSet-Cookie: XSID=; HttpOnly; Max-Age=0\r\nLocation: /login\r\n", HTTP_CT_JSON);
		http_reply(c, 302, sHeader, "{\"result\": true, \"msg\": \"注销成功！\"}", 0);
		xrtFree(sHeader);
		
	} else {
		
		// 其他请求方法返回 404 页面
		LoadPage(c, 404, HTTP_CT_HTML, "status/404.html");
		
	}
}


